<template>
  <div>
    <div v-loadmore="loadMore" id="tabContainer" ref="viewWrap" :style="wrapStyle" :class="{'mobile-style': showMobilePage}" class="view-wrap" @scroll="handleScroll">
      <div ref="resizeBox" class="tab-container rel">
        <CardItem v-for="item in computedList" :card-configs-data="getConfigData(item)" :key="item.id" :list-data="item" :class="{'pointer': !operateDisabled('view',item)}" :user-list="getUsrInfo(item)" value-key="value" class="tab-item" @click.native="operateClick('view', item, true)" @freshView="freshView">
          <div slot="btn" class="btn-wrap flex-center" @click.stop="()=>{}">
            <el-dropdown trigger="click" @visible-change="menuChange($event,item)">
              <div class="dot-btn el-dropdown-link">
                <div class="dot" />
                <div class="dot" />
                <div class="dot" />
              </div>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item :disabled="operateDisabled('view',item)" @click.native="operateClick('view', item)">查看</el-dropdown-item>
                <el-dropdown-item :disabled="operateDisabled('copy',item)" @click.native="operateClick('copy', item)">复制</el-dropdown-item>
                <el-dropdown-item :disabled="operateDisabled('edit',item)" @click.native="operateClick('edit', item)">编辑</el-dropdown-item>
                <el-dropdown-item :disabled="operateDisabled('delete',item)" @click.native="operateClick('delete', item)">删除</el-dropdown-item>
                <el-dropdown-item v-if="item.canApproval" @click.native="openAuditDialog(item,1)">通过</el-dropdown-item>
                <el-dropdown-item v-if="item.canApproval" @click.native="openAuditDialog(item,0)">退回</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </div>
        </CardItem>
      </div>
      <auditDialog
        ref="auditDialog"
        :loading="auditLoading"
        :type="type"
        :operate-data="processData.operation"
        :dialog-form-visible="auditDialogVisible"
        :content="processData.operation.content"
        :audit-schedule-data="auditScheduleData"
        @close="closeDialog"
        @handleSubmit="handleSubmit"/>
      <DetailDrawer ref="detailDrawer" @freshCardData="freshCardData"/>
    </div>
    <div v-if="listData.listLoading" class="loading marquee-text">加载中...</div>
    <img v-if="overScreen" :src="inHover ? top_active : topIcon" alt="" class="top-icon" @mouseenter="changeImg(true)" @mouseleave="changeImg()" @click="backTop">
  </div>
</template>
<script>
import auditDialog from '@/components/AuditProcess/auditDialog';
import CardItem from '@/views/legal/process/components/advancedSettings/cardList';
import DetailDrawer from '@/views/approvalModule/approvalList/components/detailDrawer';
import { getProcessList, auditSchedule, getApproveLatestInfo } from '@/api/legal';
import { approvalProcessAudit, getRowData } from '@/api/approvalModule';
import { mapState } from 'vuex';
import { processCommonStatus } from '@/filters/status';
import { showModal } from '@/utils/message';
import math from '@/utils/math';
import allowIcon from '@/assets/legalProcess/allow.png';
import refuseIcon from '@/assets/legalProcess/refuse.png';
import openIcon from '@/assets/legalProcess/open.png';
import closeIcon from '@/assets/legalProcess/close.png';
import topIcon from '@/assets/toTop.png';
import top_active from '@/assets/toTop_active.png';

export default {
  components: {
    auditDialog,
    CardItem,
    DetailDrawer
  },
  directives: { loadmore: {
    inserted(el, binding) {
      const SELECTDOWN_DOM = el;
      SELECTDOWN_DOM.addEventListener('scroll', function() {
        const CONDITION = this.scrollHeight - this.scrollTop - 20 <= this.clientHeight;
        if (CONDITION) {
          binding.value();
        }
      }, true);
    }
  }},
  props: {
    listData: {
      type: Object,
      default: () => ({
        list: [],
        cardConfig: {},
        height: 100,
        listLoading: false,
        moduleId: '',
        fieldList: []
      })
    },
    getOperateConfig: {
      type: Function,
      default: () => {}
    }
  },
  data() {
    return {
      allowIcon, refuseIcon, openIcon, closeIcon, topIcon, top_active,
      inHover: false,
      type: 0,
      processData: {
        content: '',
        operation: {}
      },
      contentHeight: 0,
      auditScheduleData: {},
      auditLoading: false,
      auditDialogVisible: false,
      processId: '',
      currentAuditItem: {},
      overScreen: false,
      fallConfig: { wrapIdName: '#tabContainer', contentIdName: '.tab-item', columns: 2, columnGap: 16, rowGap: 16 }
    };
  },
  computed: {
    ...mapState({
      'userInfo': state => state.user.userInfo,
      'showMobilePage': state => state.app.showMobilePage
    }),
    computedList: {
      get() {
        this.freshView();
        return this.listData.list;
      }
    },
    wrapStyle() {
      return {
        height: (Number(this.listData.height) + 25) + 'px',
        overflowY: 'auto'
      };
    },
    getContinueApproveStatus() {
      const continueApproveLocalKey = 'CONTINUE_APPROVE_' + this.userInfo.id;
      const getApproveLocalStatus = window.localStorage.getItem(continueApproveLocalKey);
      return ![null, 'false'].includes(getApproveLocalStatus);
    }
  },
  watch: {
    'listData.listLoading': {
      handler(val) {
        this.freshView();
      },
      deep: true,
      immediate: true
    },
    'contentHeight': {
      handler(val, oldVal) {
        if (val !== oldVal) {
          this.$nextTick(() => {
            if (this.$refs.viewWrap.clientHeight >= val) { // 预加载防止item未撑满屏幕而不显示滚动条触发不了下拉加载
              this.$emit('loadMore');
            }
          });
        }
      },
      immediate: true
    }
  },
  mounted() {
    this.$nextTick(() => {
      const resizeObserver = new ResizeObserver(entries => {
        let resizing = true;
        setTimeout(() => {
          if (resizing) {
            this.freshView();
            resizing = false;
          }
        }, 400);
      });
      resizeObserver.observe(this.$refs.resizeBox);
    });
  },
  methods: {
    closeDialog() {
      this.auditDialogVisible = false;
    },
    handleScroll() {
      this.overScreen = this.$refs.viewWrap.scrollTop > window.innerHeight;
    },
    changeImg(inHover = false) {
      this.inHover = inHover;
    },
    openDetailDrawer(row) {
      if (!row.id || !row.processId) return;
      const listParams = {
        moduleId: this.listData.moduleId,
        id: row.id,
        processId: row.processId
      };
      this.$refs['detailDrawer'].openDrawer(listParams);
    },
    freshView() {
      this.$nextTick(() => {
        this.waterFall(this.fallConfig);
      });
    },
    goNextApproveDetail(rowData, listParams = {}) {
      this.freshCardData({ moduleId: this.listData.moduleId, id: rowData.id });
      this.showMobilePage ? this.operateClick('view', rowData) : this.openDetailDrawer(listParams);
    },
    freshCardData({ moduleId, id }) {
      getRowData({ moduleId, id }).then(res => {
        if (res.code) {
          this.$emit('freshCardData', { rowData: res.data, rowId: id });
        }
      }).catch(err => {
        console.log(err);
      });
    },
    loadMore() {
      this.$emit('loadMore');
    },
    async openAuditDialog(item = {}, type) {
      if (item.existRequiredField) {
        showModal('当前节点有启用必填/填写事件，请到详情页确认审批!').then(() => {
          this.operateClick('view', item, true);
        });
        return;
      }
      this.currentAuditItem = item;
      const { processId } = item;
      if (!processId) return;
      this.processId = processId;
      const processDataRes = await getProcessList({ id: processId });
      if (processDataRes.code === 200) {
        this.processData = processDataRes.data;
      }
      const scheduleRes = await auditSchedule(processId);
      if (scheduleRes.code === 200) {
        this.auditScheduleData = scheduleRes.data && scheduleRes.data.auditInfo;
      }
      this.type = type;
      this.auditDialogVisible = true;
    },
    handleSubmit(type, data) {
      const params = Object.assign({
        id: this.processId,
        status: type,
        examineRoleId: this.processData.operation.examineRoleId
      }, data);
      approvalProcessAudit(params).then(res => {
        if (res.code === 200) {
          this.$message({ type: 'success', message: '提交成功' });
          this.closeDialog();
          this.getContinueApproveStatus ? this.continueNextApprove() : this.freshCardData({ moduleId: this.listData.moduleId, id: this.currentAuditItem.id });
        } else {
          this.$message.closeAll();
          this.$message({ type: 'error', message: res.message });
        }
        this.auditLoading = false;
      }).catch(err => {
        this.auditLoading = false;
        this.$message.closeAll();
        this.$message({ type: 'error', message: err.message });
      });
    },
    continueNextApprove() {
      const params = Object.create(null);
      params.businessType = 10;
      params.processId = this.processId;
      params.filterData = '';

      getApproveLatestInfo(params).then(res => {
        if (res.data.finished) {
          this.getContinueApproveStatus && this.$nextTick(() => {
            const message = '👍太棒了，审批已全部处理完毕';
            this.$message.closeAll();
            this.$message.success(message);
          });
          this.freshCardData({ moduleId: this.listData.moduleId, id: this.currentAuditItem.id });
        } else {
          this.goNextApproveDetail(this.currentAuditItem, res.data);
        }
      });
    },
    operateClick(key, row, isCardClick = false) {
      const item = _.cloneDeep(row);
      if (key === 'view' && !this.showMobilePage && isCardClick) {
        this.openDetailDrawer(item);
        return;
      }
      if (this.getOperateConfig) {
        const { handelClick } = this.getOperateConfig(key, item) || {};
        item.formListCard = true;
        handelClick && handelClick(item);
      }
    },
    operateDisabled(key, row) {
      const item = _.cloneDeep(row);
      const { disabled } = this.getOperateConfig(key, item) || {};
      return disabled;
    },
    menuChange(val, item) {
      this.$set(item, 'btnOpenStatus', val);
    },
    getConfigData(item = {}) {
      const { content } = JSON.parse(JSON.stringify(item));
      const fieldList = JSON.parse(JSON.stringify(this.listData.fieldList || []));
      const fixKeys = ['status', 'currentHandler', 'currentNode'];
      fieldList && fieldList.forEach(field => {
        if (fixKeys.includes(field.key)) {
          field.value = content[field.key];
          field.key === 'status' && (field.value = processCommonStatus(content[field.key]));
        } else {
          field.options = '';
          field.value = this.handelValue(field, content[field.key]);
        }
      });
      return Object.assign(_.cloneDeep(this.listData.cardConfig), { options: fieldList });
    },
    handelValue(field, value) {
      if (!value || !field.options) {
        if (field.type === 'input' && field.isNumber && field.isShowPercentage) {
          return value || value === 0 ? math.multiply(value, 100) + '%' : '';
        }
        return value;
      }
      const isNumberFormula = field.type === 'formulaInput' && !field.options.modeType;
      if (value && field.options && isNumberFormula || (field.type === 'input' && field.options.dataType === 'number')) {
        const precision = field.options.precision;
        if (precision || precision === 0) {
          return Number(Number(value).toFixed(precision));
        }
      }
      return value;
    },
    getUsrInfo(item) {
      const content = item.content || {};
      if (content.creatorAvatar && !Array.isArray(content.creatorAvatar)) return [{ avatar: content && content.creatorAvatar, id: item.creatorId }];
      return content.creatorAvatar || [];
    },
    backTop() {
      this.$nextTick(() => {
        const scrollEl = this.$refs.viewWrap;
        scrollEl.scrollTo({ top: 0, behavior: 'smooth' });
      });
    },
    waterFall({ wrapIdName, contentIdName, columnGap = 16, rowGap = 16 }) {
      const scrollWidth = 6;
      // 得到内容项集合
      const contentList = document.querySelectorAll(contentIdName);
      if (!contentList || !contentList.length) return;
      // 获得内容可用宽度(减去滚动条)
      const wrapContentWidth = document.querySelector(wrapIdName) && document.querySelector(wrapIdName).offsetWidth - scrollWidth;
      const overCOntentWidth = !!(contentList[0].offsetWidth > wrapContentWidth);
      // 得到每列宽度(也即每项内容宽度)
      const contentWidth = contentList ? overCOntentWidth ? wrapContentWidth : contentList[0].offsetWidth : 400;
      // 得到列数
      const columns = (this.showMobilePage || overCOntentWidth) ? 1 : Math.floor(wrapContentWidth / (contentWidth + columnGap));
      // 成行内容项高度集合
      const lineConentHeightList = [];

      for (let i = 0; i < contentList.length; i++) {
        // 获取内容项高度
        const height = contentList[i].clientHeight;
        // 动态设置内容项宽度
        if (this.showMobilePage || overCOntentWidth) {
          contentList[i].style.width = contentWidth + 'px';
          contentList[i].style.minWidth = contentWidth + 'px';
        }
        if (i < columns) {
          // 第一行按序布局
          contentList[i].style.top = 0;
          contentList[i].style.left = contentWidth * i + columnGap * i + 'px';

          // 将行高push到数组
          lineConentHeightList.push(height);
        } else {
          // 其他行
          // 获取数组最小的高度 和 对应索引
          const minHeight = Math.min(...lineConentHeightList);
          const index = lineConentHeightList.findIndex(
            (listH) => listH === minHeight
          );

          contentList[i].style.top = minHeight + rowGap + 'px';
          contentList[i].style.left = (contentWidth + columnGap) * index + 'px';

          // 修改最小列的高度 最小列的高度 = 当前自己的高度 + 拼接过来的高度 + 行间距
          lineConentHeightList[index] += height + rowGap;
        }
      }
      this.contentHeight = Math.max(...lineConentHeightList);
      this.$forceUpdate();
    }
  }
};
</script>
<style lang="scss" scoped>
.view-wrap {
  padding: 6px;
  transform: translate(-6px, -6px);
  @include scrollBar($x: hidden, $y: auto, $width: 6px);
}
.tab-container .tab-item {
  position: absolute;
  height: auto;
}
.tab-item:hover {
  .btn-wrap {
    display: flex;
    .dot-btn {
      border: 1px solid #ddd;
      border-radius: 4px;
      background: #fff;
    }
  }
}
@keyframes marquee {
  0% {
    background-position: -100% 0;
  }
  100% {
    background-position: 130% 0;
  }
}

.marquee-text {
  background: #999 linear-gradient(-135deg, transparent 25%, transparent 40%, #406eff 40%, #406eff 60%, transparent 60%, transparent) no-repeat;
  background-size: 30px 30px;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: marquee 1s linear infinite;
}
.loading {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 5px;
  font-size: 14px;
}

.btn-wrap {
  position: absolute;
  right: 6px;
  top: 6px;
  padding: 2px;
  cursor: pointer;
}
.btn-icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}
.menu-icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  margin-left: 8px;
}
.dot-btn {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 32px;
  height: 20px;
  padding: 2px;
  .dot {
    width: 4px;
    height: 4px;
    background: #aeb6c7;
    border-radius: 50%;
    margin-right: 3px;
  }
  .dot:last-child {
    margin: 0;
  }
}

.mobile-style {
  .tab-item {
    margin: 0 12px;
  }
  .btn-wrap {
    display: flex !important;

  }
}
::v-deep {
  .card-file-container {
    padding-top: 12px
  }
}
.top-icon {
  position: fixed;
  right: 29px;
  bottom: 19px;
  width: 38px;
  height: 38px;
  cursor: pointer;
}
</style>
